/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.faces.config;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import javax.faces.application.ResourceHandler;
import javax.faces.application.ViewHandler;
import javax.faces.application.StateManager;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;

import com.sun.faces.util.FacesLogger;
import com.sun.faces.util.Util;

import java.util.HashMap;
import javax.faces.component.UIInput;
import javax.faces.validator.BeanValidator;
import javax.faces.view.facelets.ResourceResolver;

/** Class Documentation */
public class WebConfiguration
{

        // Log instance for this class
        private static final Logger LOGGER = FacesLogger.CONFIG.getLogger();

        // A Simple regular expression of allowable boolean values
        private static final Pattern ALLOWABLE_BOOLEANS = Pattern
                        .compile("true|false");

        // Key under which we store our WebConfiguration instance.
        private static final String WEB_CONFIG_KEY = "com.sun.faces.config.WebConfiguration";

        // Logging level. Defaults to FINE
        private Level loggingLevel = Level.FINE;

        private Map<BooleanWebContextInitParameter, Boolean> booleanContextParameters = new EnumMap<BooleanWebContextInitParameter, Boolean>(
                        BooleanWebContextInitParameter.class);

        private Map<WebContextInitParameter, String> contextParameters = new EnumMap<WebContextInitParameter, String>(
                        WebContextInitParameter.class);

        private Map<WebEnvironmentEntry, String> envEntries = new EnumMap<WebEnvironmentEntry, String>(
                        WebEnvironmentEntry.class);

        private Map<WebContextInitParameter, String[]> cachedListParams;

        private List<String> setParams = new ArrayList<String>();

        private ServletContext servletContext;

        // ------------------------------------------------------------ Constructors

        private WebConfiguration(ServletContext servletContext)
        {

                this.servletContext = servletContext;

                String contextName = getServletContextName();

                initSetList(servletContext);
                processBooleanParameters(servletContext, contextName);
                processInitParameters(servletContext, contextName);
                if (canProcessJndiEntries())
                {
                        processJndiEntries(contextName);
                }

                // build the cache of list type params
                cachedListParams = new HashMap<WebContextInitParameter, String[]>(3);
                getOptionValue(WebContextInitParameter.ResourceExcludes, " ");
                getOptionValue(WebContextInitParameter.DefaultSuffix, " ");
                getOptionValue(WebContextInitParameter.FaceletsViewMappings, ";");

        }

        // ---------------------------------------------------------- Public Methods

        /**
         * Return the WebConfiguration instance for this application passing the
         * result of FacesContext.getCurrentInstance().getExternalContext() to
         * {@link #getInstance(javax.faces.context.ExternalContext)}.
         * 
         * @return the WebConfiguration for this application or <code>null</code> if
         *         no FacesContext is available.
         */
        public static WebConfiguration getInstance()
        {

                FacesContext facesContext = FacesContext.getCurrentInstance();
                return getInstance(facesContext.getExternalContext());

        }

        /**
         * Return the WebConfiguration instance for this application.
         * 
         * @param extContext
         *            the ExternalContext for this request
         * @return the WebConfiguration for this application
         */
        public static WebConfiguration getInstance(ExternalContext extContext)
        {

                WebConfiguration config = (WebConfiguration) extContext
                                .getApplicationMap().get(WEB_CONFIG_KEY);
                if (config == null)
                {
                        return getInstance((ServletContext) extContext.getContext());
                }
                else
                {
                        return config;
                }

        }

        /**
         * Return the WebConfiguration instance for this application.
         * 
         * @param servletContext
         *            the ServletContext
         * @return the WebConfiguration for this application or <code>null</code> if
         *         no WebConfiguration could be located
         */
        public static WebConfiguration getInstance(ServletContext servletContext)
        {

                WebConfiguration webConfig = (WebConfiguration) servletContext
                                .getAttribute(WEB_CONFIG_KEY);

                if (webConfig == null)
                {
                        webConfig = new WebConfiguration(servletContext);
                        servletContext.setAttribute(WEB_CONFIG_KEY, webConfig);
                }
                return webConfig;

        }

        /**
         * @return The <code>ServletContext</code> originally used to construct this
         *         WebConfiguration instance
         */
        public ServletContext getServletContext()
        {

                return servletContext;

        }

        /**
         * Obtain the value of the specified boolean parameter
         * 
         * @param param
         *            the parameter of interest
         * @return the value of the specified boolean parameter
         */
        public boolean isOptionEnabled(BooleanWebContextInitParameter param)
        {

                if (booleanContextParameters.get(param) != null)
                {
                        return booleanContextParameters.get(param);
                }
                else
                {
                        return param.getDefaultValue();
                }

        }

        /**
         * Obtain the value of the specified parameter
         * 
         * @param param
         *            the parameter of interest
         * @return the value of the specified parameter
         */
        public String getOptionValue(WebContextInitParameter param)
        {
                String result = contextParameters.get(param);

                if (null == result)
                {
                        WebContextInitParameter alternate = param.getAlternate();
                        if (null != alternate)
                        {
                                result = contextParameters.get(alternate);
                        }
                }

                return result;

        }

        public String[] getOptionValue(WebContextInitParameter param, String sep)
        {
                String[] result;

                assert (null != cachedListParams);
                if (null == (result = cachedListParams.get(param)))
                {
                        String value = getOptionValue(param);
                        if (null == value)
                        {
                                result = new String[0];
                        }
                        else
                        {
                                result = Util.split(value, sep);
                        }
                        cachedListParams.put(param, result);
                }

                return result;
        }

        /**
         * Obtain the value of the specified env-entry
         * 
         * @param entry
         *            the env-entry of interest
         * @return the value of the specified env-entry
         */
        public String getEnvironmentEntry(WebEnvironmentEntry entry)
        {

                return envEntries.get(entry);

        }

        /**
         * @param param
         *            the init parameter of interest
         * @return <code>true</code> if the parameter was explicitly set, otherwise,
         *         <code>false</code>
         */
        public boolean isSet(WebContextInitParameter param)
        {

                return isSet(param.getQualifiedName());

        }

        /**
         * @param param
         *            the init parameter of interest
         * @return <code>true</code> if the parameter was explicitly set, otherwise,
         *         <code>false</code>
         */
        public boolean isSet(BooleanWebContextInitParameter param)
        {

                return isSet(param.getQualifiedName());

        }

        /**
         * @return the name of this application
         */
        public String getServletContextName()
        {

                if (servletContext.getMajorVersion() == 2
                                && servletContext.getMinorVersion() <= 4)
                {
                        return servletContext.getServletContextName();
                }
                else
                {
                        return servletContext.getContextPath();
                }

        }

        public void overrideContextInitParameter(
                        BooleanWebContextInitParameter param, boolean value)
        {

                if (param == null) { return; }
                boolean oldVal = booleanContextParameters.put(param, value);
                if (LOGGER.isLoggable(Level.FINE) && oldVal != value)
                {
                        LOGGER
                                        .log(
                                                        Level.FINE,
                                                        "Overriding init parameter {0}.  Changing from {1} to {2}.",
                                                        new Object[]
                                                        {
                                                                        param.getQualifiedName(), oldVal, value
                                                        });
                }

        }

        public void overrideContextInitParameter(WebContextInitParameter param,
                        String value)
        {

                if (param == null || value == null || value.length() == 0) { return; }
                value = value.trim();
                String oldVal = contextParameters.put(param, value);
                cachedListParams.remove(param);
                if (oldVal != null)
                {
                        if (LOGGER.isLoggable(Level.FINE) && !(oldVal.equals(value)))
                        {
                                LOGGER
                                                .log(
                                                                Level.FINE,
                                                                "Overriding init parameter {0}.  Changing from {1} to {2}.",
                                                                new Object[]
                                                                {
                                                                                param.getQualifiedName(), oldVal, value
                                                                });
                        }
                }

        }

        // ------------------------------------------------- Package Private Methods

        static void clear(ServletContext servletContext)
        {

                servletContext.removeAttribute(WEB_CONFIG_KEY);

        }

        // --------------------------------------------------------- Private Methods

        /**
         * <p>
         * Is the configured value valid against the default boolean pattern.
         * </p>
         * 
         * @param param
         *            the boolean parameter
         * @param value
         *            the configured value
         * @return <code>true</code> if the value is valid, otherwise
         *         <code>false</code>
         */
        private boolean isValueValid(BooleanWebContextInitParameter param,
                        String value)
        {

                if (!ALLOWABLE_BOOLEANS.matcher(value).matches())
                {
                        if (LOGGER.isLoggable(Level.WARNING))
                        {
                                LOGGER.log(Level.WARNING,
                                                "jsf.config.webconfig.boolconfig.invalidvalue",
                                                new Object[]
                                                {
                                                                value, param.getQualifiedName(), "true|false"
                                                });
                        }
                        return false;
                }

                return true;

        }

        /**
         * <p>
         * Process all boolean context initialization parameters.
         * </p>
         * 
         * @param servletContext
         *            the ServletContext of interest
         * @param contextName
         *            the context name
         */
        private void processBooleanParameters(ServletContext servletContext,
                        String contextName)
        {

                // process boolean contxt parameters
                for (BooleanWebContextInitParameter param : BooleanWebContextInitParameter
                                .values())
                {
                        String strValue = servletContext.getInitParameter(param
                                        .getQualifiedName());
                        boolean value;

                        if (strValue != null && strValue.length() > 0
                                        && param.isDeprecated())
                        {
                                BooleanWebContextInitParameter alternate = param.getAlternate();
                                if (LOGGER.isLoggable(Level.WARNING))
                                {
                                        if (alternate != null)
                                        {
                                                LOGGER.log(Level.WARNING,
                                                                "jsf.config.webconfig.param.deprecated",
                                                                new Object[]
                                                                {
                                                                                contextName, param.getQualifiedName(),
                                                                                alternate.getQualifiedName()
                                                                });
                                        }
                                        else
                                        {
                                                LOGGER
                                                                .log(
                                                                                Level.WARNING,
                                                                                "jsf.config.webconfig.param.deprecated.no_replacement",
                                                                                new Object[]
                                                                                {
                                                                                                contextName,
                                                                                                param.getQualifiedName()
                                                                                });
                                        }
                                }

                                if (alternate != null)
                                {
                                        if (isValueValid(param, strValue))
                                        {
                                                value = Boolean.valueOf(strValue);
                                        }
                                        else
                                        {
                                                value = param.getDefaultValue();
                                        }

                                        if (LOGGER.isLoggable(Level.INFO) && alternate != null)
                                        {
                                                LOGGER
                                                                .log(
                                                                                Level.INFO,
                                                                                ((value) ? "jsf.config.webconfig.configinfo.reset.enabled"
                                                                                                : "jsf.config.webconfig.configinfo.reset.disabled"),
                                                                                new Object[]
                                                                                {
                                                                                                contextName,
                                                                                                alternate.getQualifiedName()
                                                                                });
                                        }

                                        booleanContextParameters.put(alternate, value);
                                }
                                continue;
                        }

                        if (!param.isDeprecated())
                        {
                                if (strValue == null)
                                {
                                        value = param.getDefaultValue();
                                }
                                else
                                {
                                        if (isValueValid(param, strValue))
                                        {
                                                value = Boolean.valueOf(strValue);
                                        }
                                        else
                                        {
                                                value = param.getDefaultValue();
                                        }
                                }

                                // first param processed should be
                                // com.sun.faces.displayConfiguration
                                if (BooleanWebContextInitParameter.DisplayConfiguration
                                                .equals(param)
                                                && value)
                                {
                                        loggingLevel = Level.INFO;
                                }

                                if (LOGGER.isLoggable(loggingLevel))
                                {
                                        LOGGER
                                                        .log(
                                                                        loggingLevel,
                                                                        ((value) ? "jsf.config.webconfig.boolconfiginfo.enabled"
                                                                                        : "jsf.config.webconfig.boolconfiginfo.disabled"),
                                                                        new Object[]
                                                                        {
                                                                                        contextName,
                                                                                        param.getQualifiedName()
                                                                        });
                                }

                                booleanContextParameters.put(param, value);
                        }

                }

        }

        /**
         * Adds all com.sun.faces init parameter names to a list. This allows
         * callers to determine if a parameter was explicitly set.
         * 
         * @param servletContext
         *            the ServletContext of interest
         */
        private void initSetList(ServletContext servletContext)
        {

                for (Enumeration e = servletContext.getInitParameterNames(); e
                                .hasMoreElements();)
                {
                        String name = e.nextElement().toString();
                        if (name.startsWith("com.sun.faces"))
                        {
                                setParams.add(name);
                        }
                }

        }

        /**
         * @param name
         *            the param name
         * @return <code>true</code> if the name was explicitly specified
         */
        private boolean isSet(String name)
        {

                return setParams.contains(name);

        }

        /**
         * <p>
         * Process all non-boolean context initialization parameters.
         * </p>
         * 
         * @param servletContext
         *            the ServletContext of interest
         * @param contextName
         *            the context name
         */
        private void processInitParameters(ServletContext servletContext,
                        String contextName)
        {

                for (WebContextInitParameter param : WebContextInitParameter.values())
                {
                        String value = servletContext.getInitParameter(param
                                        .getQualifiedName());

                        if (value != null && value.length() > 0 && param.isDeprecated())
                        {
                                WebContextInitParameter alternate = param.getAlternate();
                                if (LOGGER.isLoggable(Level.WARNING))
                                {
                                        if (alternate != null)
                                        {
                                                LOGGER.log(Level.WARNING,
                                                                "jsf.config.webconfig.param.deprecated",
                                                                new Object[]
                                                                {
                                                                                contextName, param.getQualifiedName(),
                                                                                alternate.getQualifiedName()
                                                                });
                                        }
                                        else
                                        {
                                                LOGGER
                                                                .log(
                                                                                Level.WARNING,
                                                                                "jsf.config.webconfig.param.deprecated.no_replacement",
                                                                                new Object[]
                                                                                {
                                                                                                contextName,
                                                                                                param.getQualifiedName()
                                                                                });
                                        }
                                }

                                if (alternate != null)
                                {
                                        if (LOGGER.isLoggable(Level.INFO))
                                        {
                                                LOGGER.log(Level.INFO,
                                                                "jsf.config.webconfig.configinfo.reset",
                                                                new Object[]
                                                                {
                                                                                contextName,
                                                                                alternate.getQualifiedName(), value
                                                                });
                                        }

                                        contextParameters.put(alternate, value);
                                }
                                continue;
                        }

                        if ((value == null || value.length() == 0) && !param.isDeprecated())
                        {
                                value = param.getDefaultValue();
                        }
                        if (value == null || value.length() == 0)
                        {
                                continue;
                        }

                        if (value.length() > 0)
                        {
                                if (LOGGER.isLoggable(loggingLevel))
                                {
                                        LOGGER.log(loggingLevel, "jsf.config.webconfig.configinfo",
                                                        new Object[]
                                                        {
                                                                        contextName, param.getQualifiedName(),
                                                                        value
                                                        });

                                }
                                contextParameters.put(param, value);
                        }
                        else
                        {
                                if (LOGGER.isLoggable(loggingLevel))
                                {
                                        LOGGER.log(loggingLevel,
                                                        "jsf.config.webconfig.option.notconfigured",
                                                        new Object[]
                                                        {
                                                                        contextName, param.getQualifiedName()
                                                        });
                                }
                        }

                }

        }

        /**
         * <p>
         * Process all JNDI entries.
         * </p>
         * 
         * @param contextName
         *            the context name
         */
        private void processJndiEntries(String contextName)
        {
/*
 * This section has been disabled due to incompatibilities with Google App Engine 1.2.6.
                Context initialContext = null;
                try
                {
                        initialContext = new InitialContext();
                }
                catch (NamingException ne)
                {
                        if (LOGGER.isLoggable(Level.WARNING))
                        {
                                LOGGER.log(Level.WARNING, ne.toString(), ne);
                        }
                }

                if (initialContext != null)
                {
                        // process environment entries
                        for (WebEnvironmentEntry entry : WebEnvironmentEntry.values())
                        {
                                String entryName = entry.getQualifiedName();
                                String value = null;

                                try
                                {
                                        value = (String) initialContext.lookup(entryName);
                                }
                                catch (NamingException root)
                                {
                                        if (LOGGER.isLoggable(Level.FINE))
                                        {
                                                LOGGER.fine(root.toString());
                                        }
                                }

                                if (value != null)
                                {
                                        if (LOGGER.isLoggable(Level.INFO))
                                        {
                                                // special logic for ClientStateSavingPassword
                                                if (!entry
                                                                .equals(WebEnvironmentEntry.ClientStateSavingPassword))
                                                {
                                                        if (LOGGER.isLoggable(loggingLevel))
                                                        {
                                                                LOGGER.log(loggingLevel,
                                                                                "jsf.config.webconfig.enventryinfo",
                                                                                new Object[]
                                                                                {
                                                                                                contextName, entryName, value
                                                                                });
                                                        }
                                                }
                                                else
                                                {
                                                        if (LOGGER.isLoggable(loggingLevel))
                                                        {
                                                                LOGGER
                                                                                .log(
                                                                                                loggingLevel,
                                                                                                "jsf.config.webconfig.enventry.clientencrypt",
                                                                                                contextName);
                                                        }
                                                }
                                        }
                                        envEntries.put(entry, value);
                                }
                        }
                }
*/
        }

        private boolean canProcessJndiEntries()
        {

                /*
                 * This section has been disabled due to incompatibilities with Google App Engine 1.2.6
                try
                {
                        Util.getCurrentLoader(this)
                                        .loadClass("javax.naming.InitialContext");
                }
                catch (Exception e)
                {
                */
                        if (LOGGER.isLoggable(Level.FINE))
                        {
                                LOGGER
                                                .fine("javax.naming is forced unavailable.  JNDI entries related to Mojarra configuration will not be processed.");
                        }
                        return false;
                /*
                }
                return true;
                */

        }

        // ------------------------------------------------------------------- Enums

        /**
         * <p>
         * An <code>enum</code> of all non-boolean context initalization parameters
         * recognized by the implementation.
         * </p>
         */
        public enum WebContextInitParameter
        {

                // implementation note:
                // if a parameter is to be deprecated,
                // then the <name>Deprecated enum element
                // *must* appear after the one that is taking
                // its place. The reporting logic depends on this

                ManagedBeanFactoryDecorator(
                                "com.sun.faces.managedBeanFactoryDecoratorClass", ""), StateSavingMethod(
                                "javax.faces.STATE_SAVING_METHOD", "server"), FaceletsSuffix(
                                ViewHandler.FACELETS_SUFFIX_PARAM_NAME,
                                ViewHandler.DEFAULT_FACELETS_SUFFIX), DefaultSuffix(
                                ViewHandler.DEFAULT_SUFFIX_PARAM_NAME,
                                ViewHandler.DEFAULT_SUFFIX), JavaxFacesConfigFiles(
                                "javax.faces.CONFIG_FILES", ""), JavaxFacesProjectStage(
                                "javax.faces.PROJECT_STAGE", "Production"), AlternateLifecycleId(
                                "javax.faces.LIFECYCLE_ID", ""), ResourceExcludes(
                                ResourceHandler.RESOURCE_EXCLUDES_PARAM_NAME,
                                ResourceHandler.RESOURCE_EXCLUDES_DEFAULT_VALUE + " .groovy"), NumberOfViews(
                                "com.sun.faces.numberOfViewsInSession", "15"), NumberOfViewsDeprecated(
                                "com.sun.faces.NUMBER_OF_VIEWS_IN_SESSION", "15", true,
                                NumberOfViews), NumberOfLogicalViews(
                                "com.sun.faces.numberOfLogicalViews", "15"), NumberOfLogicalViewsDeprecated(
                                "com.sun.faces.NUMBER_OF_VIEWS_IN_LOGICAL_VIEW_IN_SESSION",
                                "15", true, NumberOfLogicalViews), NumberOfConcurrentFlashUsers(
                                "com.sun.faces.numberOfConcerrentFlashUsers", "5000"), NumberOfFlashesBetweenFlashReapings(
                                "com.sun.faces.numberOfFlashesBetweenFlashReapings", "5000"), InjectionProviderClass(
                                "com.sun.faces.injectionProvider", ""), SerializationProviderClass(
                                "com.sun.faces.serializationProvider", ""), ResponseBufferSize(
                                "com.sun.faces.responseBufferSize", "1024"), FaceletsBufferSize(
                                "javax.faces.FACELETS_BUFFER_SIZE", "1024", true,
                                ResponseBufferSize), FaceletsBufferSizeDeprecated(
                                "facelets.BUFFER_SIZE", "1024", true, FaceletsBufferSize), ClientStateWriteBufferSize(
                                "com.sun.faces.clientStateWriteBufferSize", "8192"), ResourceBufferSize(
                                "com.sun.faces.resourceBufferSize", "2048"), ExpressionFactory(
                                "com.sun.faces.expressionFactory",
                                "com.sun.el.ExpressionFactoryImpl"), ClientStateTimeout(
                                "com.sun.faces.clientStateTimeout", ""), DefaultResourceMaxAge(
                                "com.sun.faces.defaultResourceMaxAge", "604800"), ResourceUpdateCheckPeriod(
                                "com.sun.faces.resourceUpdateCheckPeriod", "5" // in minutes
                ), CompressableMimeTypes("com.sun.faces.compressableMimeTypes", ""), DisableUnicodeEscaping(
                                "com.sun.faces.disableUnicodeEscaping", "auto"), FaceletsDefaultRefreshPeriod(
                                "javax.faces.FACELETS_REFRESH_PERIOD", "2"), FaceletsDefaultRefreshPeriodDeprecated(
                                "facelets.REFRESH_PERIOD", "2", true,
                                FaceletsDefaultRefreshPeriod), FaceletsResourceResolver(
                                ResourceResolver.FACELETS_RESOURCE_RESOLVER_PARAM_NAME, ""), FaceletsResourceResolverDeprecated(
                                "facelets.RESOURCE_RESOLVER", "", true,
                                FaceletsResourceResolver), FaceletsViewMappings(
                                ViewHandler.FACELETS_VIEW_MAPPINGS_PARAM_NAME, ""), FaceletsViewMappingsDeprecated(
                                "facelets.VIEW_MAPPINGS", "", true, FaceletsViewMappings), FaceletsLibraries(
                                "javax.faces.FACELETS_LIBRARIES", ""), FaceletsLibrariesDeprecated(
                                "facelets.LIBRARIES", "", true, FaceletsLibraries), FaceletsDecorators(
                                "javax.faces.FACELETS_DECORATORS", ""), FaceletsDecoratorsDeprecated(
                                "facelets.DECORATORS", "", true, FaceletsDecorators), DuplicateJARPattern(
                                "com.sun.faces.duplicateJARPattern", ""), ValidateEmptyFields(
                                UIInput.VALIDATE_EMPTY_FIELDS_PARAM_NAME, "auto"), FullStateSavingViewIds(
                                StateManager.FULL_STATE_SAVING_VIEW_IDS_PARAM_NAME, ""), AnnotationScanPackages(
                                "com.sun.faces.annotationScanPackages", ""), FaceletFactory(
                                "com.sun.faces.faceletFactory", "");

                private String defaultValue;
                private String qualifiedName;
                private WebContextInitParameter alternate;
                private boolean deprecated;

                // ---------------------------------------------------------- Public
                // Methods

                public String getDefaultValue()
                {

                        return defaultValue;

                }

                public String getQualifiedName()
                {

                        return qualifiedName;

                }

                // ------------------------------------------------- Package Private
                // Methods

                WebContextInitParameter(String qualifiedName, String defaultValue)
                {

                        this(qualifiedName, defaultValue, false, null);

                }

                WebContextInitParameter(String qualifiedName, String defaultValue,
                                boolean deprecated, WebContextInitParameter alternate)
                {

                        this.qualifiedName = qualifiedName;
                        this.defaultValue = defaultValue;
                        this.deprecated = deprecated;
                        this.alternate = alternate;

                }

                // --------------------------------------------------------- Private
                // Methods

                private WebContextInitParameter getAlternate()
                {

                        return alternate;

                }

                private boolean isDeprecated()
                {

                        return deprecated;

                }

        }

        /**
         * <p>
         * An <code>enum</code> of all boolean context initalization parameters
         * recognized by the implementation.
         * </p>
         */
        public enum BooleanWebContextInitParameter
        {

                // implementation note:
                // if a parameter is to be deprecated,
                // then the <name>Deprecated enum element
                // *must* appear after the one that is taking
                // its place. The reporting logic depends on this

                DisplayConfiguration("com.sun.faces.displayConfiguration", false), ValidateFacesConfigFiles(
                                "com.sun.faces.validateXml", false), VerifyFacesConfigObjects(
                                "com.sun.faces.verifyObjects", false), ForceLoadFacesConfigFiles(
                                "com.sun.faces.forceLoadConfiguration", false), DisableArtifactVersioning(
                                "com.sun.faces.disableVersionTracking", false, true, null), EnableHtmlTagLibraryValidator(
                                "com.sun.faces.enableHtmlTagLibValidator", false), EnableCoreTagLibraryValidator(
                                "com.sun.faces.enableCoreTagLibValidator", false), PreferXHTMLContentType(
                                "com.sun.faces.preferXHTML", false), PreferXHTMLContextTypeDeprecated(
                                "com.sun.faces.PreferXHTML", false, true,
                                PreferXHTMLContentType), CompressViewState(
                                "com.sun.faces.compressViewState", true), CompressViewStateDeprecated(
                                "com.sun.faces.COMPRESS_STATE", true, true, CompressViewState), CompressJavaScript(
                                "com.sun.faces.compressJavaScript", true), ExternalizeJavaScriptDeprecated(
                                "com.sun.faces.externalizeJavaScript", true, true, null), SendPoweredByHeader(
                                "com.sun.faces.sendPoweredByHeader", true), EnableJSStyleHiding(
                                "com.sun.faces.enableJSStyleHiding", false), EnableScriptInAttributeValue(
                                "com.sun.faces.enableScriptsInAttributeValues", true), WriteStateAtFormEnd(
                                "com.sun.faces.writeStateAtFormEnd", true), EnableLazyBeanValidation(
                                "com.sun.faces.enableLazyBeanValidation", true), EnableLoadBundle11Compatibility(
                                "com.sun.faces.enabledLoadBundle11Compatibility", false), EnableRestoreView11Compatibility(
                                "com.sun.faces.enableRestoreView11Compatibility", false), SerializeServerState(
                                "com.sun.faces.serializeServerState", false), EnableViewStateIdRendering(
                                "com.sun.faces.enableViewStateIdRendering", true), RegisterConverterPropertyEditors(
                                "com.sun.faces.registerConverterPropertyEditors", false), EnableGroovyScripting(
                                "com.sun.faces.enableGroovyScripting", false), DisableFaceletJSFViewHandler(
                                "javax.faces.DISABLE_FACELET_JSF_VIEWHANDLER", false), DisableDefaultBeanValidator(
                                BeanValidator.DISABLE_DEFAULT_BEAN_VALIDATOR_PARAM_NAME, false), DateTimeConverterUsesSystemTimezone(
                                "javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE",
                                false), FaceletsSkipComments(
                                "javax.faces.FACELETS_SKIP_COMMENTS", false), FaceletsSkipCommentsDeprecated(
                                "facelets.SKIP_COMMENTS", false, true, FaceletsSkipComments), PartialStateSaving(
                                StateManager.PARTIAL_STATE_SAVING_PARAM_NAME, true), GenerateUniqueServerStateIds(
                                "com.sun.faces.generateUniqueServerStateIds", true), AutoCompleteOffOnViewState(
                                "com.sun.faces.autoCompleteOffOnViewState", true), EnableThreading(
                                "com.sun.faces.enableThreading", true), AllowTextChildren(
                                "com.sun.faces.allowTextChildren", false);

                private BooleanWebContextInitParameter alternate;

                private String qualifiedName;
                private boolean defaultValue;
                private boolean deprecated;

                // ---------------------------------------------------------- Public
                // Methods

                public boolean getDefaultValue()
                {

                        return defaultValue;

                }

                public String getQualifiedName()
                {

                        return qualifiedName;

                }

                // ------------------------------------------------- Package Private
                // Methods

                BooleanWebContextInitParameter(String qualifiedName,
                                boolean defaultValue)
                {

                        this(qualifiedName, defaultValue, false, null);

                }

                BooleanWebContextInitParameter(String qualifiedName,
                                boolean defaultValue, boolean deprecated,
                                BooleanWebContextInitParameter alternate)
                {

                        this.qualifiedName = qualifiedName;
                        this.defaultValue = defaultValue;
                        this.deprecated = deprecated;
                        this.alternate = alternate;

                }

                // --------------------------------------------------------- Private
                // Methods

                private BooleanWebContextInitParameter getAlternate()
                {

                        return alternate;

                }

                private boolean isDeprecated()
                {

                        return deprecated;

                }

        }

        /**
         * <p>
         * An <code>enum</code> of all environment entries (specified in the
         * web.xml) recognized by the implemenetation.
         * </p>
         */
        public enum WebEnvironmentEntry
        {

                ClientStateSavingPassword("ClientStateSavingPassword"), ProjectStage(
                                javax.faces.application.ProjectStage.PROJECT_STAGE_JNDI_NAME);

                private static final String JNDI_PREFIX = "java:comp/env/";
                private String qualifiedName;

                // ---------------------------------------------------------- Public
                // Methods

                public String getQualifiedName()
                {

                        return qualifiedName;

                }

                // ------------------------------------------------- Package Private
                // Methods

                WebEnvironmentEntry(String qualifiedName)
                {

                        if (qualifiedName.startsWith(JNDI_PREFIX))
                        {
                                this.qualifiedName = qualifiedName;
                        }
                        else
                        {
                                this.qualifiedName = JNDI_PREFIX + qualifiedName;
                        }

                }

        }

        /**
         * <p>
         * An <code>enum</code> of all possible values for the
         * <code>disableUnicodeEscaping</code> configuration parameter.
         * </p>
         */
        public enum DisableUnicodeEscaping
        {
                True("true"), False("false"), Auto("auto");

                private final String value;

                DisableUnicodeEscaping(String value)
                {
                        this.value = value;
                }

                public static DisableUnicodeEscaping getByValue(String value)
                {
                        for (DisableUnicodeEscaping disableUnicodeEscaping : DisableUnicodeEscaping
                                        .values())
                        {
                                if (disableUnicodeEscaping.value.equals(value)) { return disableUnicodeEscaping; }
                        }

                        return null;
                }
        }

} // END WebConfiguration